import type { Directive } from 'vue'
import './ripple.scss'

function computeRippleStyles(element: any, event: MouseEvent) {
    const { top, left } = element.getBoundingClientRect()
    const { clientWidth, clientHeight } = element

    const radius = Math.sqrt(clientWidth ** 2 + clientHeight ** 2) / 2
    const size = radius * 2

    const localX = event.clientX - left
    const localY = event.clientY - top

    const centerX = (clientWidth - radius * 2) / 2
    const centerY = (clientHeight - radius * 2) / 2

    const x = localX - radius
    const y = localY - radius

    return { x, y, centerX, centerY, size }

}

function createRipple(el: any) {
    return (event: MouseEvent) => {
        const container = el
        const { x, y, centerX, centerY, size } = computeRippleStyles(container, event)
        const ripple = document.createElement('div')
        ripple.classList.add('ripple-circle')
        ripple.style.opacity = `0`
        ripple.style.transform = `translate(${x}px, ${y}px) scale3d(.3, .3, .3)`
        ripple.style.width = `${size}px`
        ripple.style.height = `${size}px`
        ripple.dataset.createdAt = String(performance.now())

        const { position } = window.getComputedStyle(container)
        container.style.overflow = 'hidden'
        position === 'static' && (container.style.position = 'relative')

        container.appendChild(ripple)

        window.setTimeout(() => {
            ripple.style.transform = `translate(${centerX}px, ${centerY}px) scale3d(1, 1, 1)`
            ripple.style.opacity = `.25`
        })
    }
}


function removeRipple(el: any) {
    return () => {
        const container = el
        const ripples = container.querySelectorAll('.ripple-circle')
        if (!ripples.length) {
            return
        }

        const lastRipple = ripples[ripples.length - 1]
        const delay = 300 - performance.now() + Number(lastRipple.dataset.createdAt)

        setTimeout(() => {
            lastRipple.style.opacity = `0`
            setTimeout(() => lastRipple.parentNode?.removeChild(lastRipple), 300)
        }, delay)
    }
}




const ripple: Directive = {
    mounted(el, binding) {
        el.addEventListener('mousedown', createRipple(el))
        document.addEventListener('mouseup', removeRipple(el))
    },
    unmounted(el) {
        el.removeEventListener('mousedown', createRipple(el))
        document.removeEventListener('mouseup', removeRipple(el))
    }
}

export default ripple
